import java.io.Console;
import java.sql.PreparedStatement;
import java.io.IOException;
import java.sql.*;
import java.util.Arrays;
import java.util.Properties;
import java.util.regex.*;
import java.security.SecureRandom;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.math.BigInteger;
import java.io.UnsupportedEncodingException;

// Class handling user registration
public class UserRegistration {

	// variables
	private static String username = null;
	private static String password = null;
	private static char[] salt = new char[16];
	private static String hash = null;
	private static String email = null;
	private static String name = null;
	private static String address = null;
	
	// Insert new user in database
	public static boolean insertUser() throws ClassNotFoundException,SQLException {
		
		// Create connection to the database
		Connection c = mysqlConnection.connect();
		
		// Insert User
		PreparedStatement insert = c.prepareStatement("INSERT INTO User (Username,Password,Salt,Email,Name,Address) VALUES (?,?,?,?,?,?)");
		insert.setString(1, username);
		insert.setString(2, hash);
		insert.setString(3, new String(salt));
		insert.setString(4, email);	
		insert.setString(5, name);
		insert.setString(6, address);
		int i = insert.executeUpdate();
		
		return true;
	}
	
	// Username prompt
	public static boolean usernamePrompt() throws ClassNotFoundException,SQLException{
		
		// Use the user's environment console
		Console console = System.console();
		
		// variables
		boolean hasSpecialChar = false;
		boolean validUser = false;
		String u = null;
		
		// Create a connection
		Connection c = mysqlConnection.connect();
		
		Pattern p = Pattern.compile("[^a-zA-Z0-9]");
		
		// Check if username is 16 alphanumeric characters and is not taken
		do {
			System.out.println("\nPlease enter a username of no more than 16 alphanumeric characters:");
			u = console.readLine("username: ");
			hasSpecialChar = p.matcher(u).find();
			
			// 16 alphanumeric?
			if (hasSpecialChar || u.length() > 16) {
				System.out.println("\nPlease use only 16 or less alphanumeric characters.");
				continue;
			}
			
			// Taken already?
			PreparedStatement user = c.prepareStatement("SELECT Username FROM User WHERE Username=?");
			user.setString(1, u);
			ResultSet r = user.executeQuery();
			
			if (r.next()) {
				System.out.println("\nUsername is already taken. Please choose another.");
				continue;
			}
			
			validUser = true;
		
		} while (!validUser);
		
		username = u;
		
		return true;
	}
	
	// Password prompt
	public static boolean passwordPrompt() throws ClassNotFoundException,SQLException {
		
		// Use user's console
		Console console = System.console();
		
		// variables
		char[] pass1;
		char[] pass2;
		boolean validPass = false;
		
		// Check if password is right length
		do {
			System.out.println("\nPlease make your password 8 or more characters and no more than 20.");
			pass1 = console.readPassword("password: ");
			
			if (!(pass1.length >= 8 && pass1.length <= 20)) {
				continue;
			}
			else {
				validPass = true;
			}
		} while (!validPass);
		
		// Reset variables
		validPass = false;
		
		// Do the passwords match?
		do {
			pass2 = console.readPassword("\nretype password: ");
			
					
			if (Arrays.equals(pass1, pass2)) {
				validPass = true;
			}
		} while (!validPass);
		
		// save the password for later
		password = new String(pass1);
		
		return true;
	}
	
	// Salt and Hash the password
	public static boolean saltHash () throws NoSuchAlgorithmException, UnsupportedEncodingException{
	
		// Use secure random numbers for salt
		SecureRandom r = new SecureRandom();
		// Create random 16 byte salt
		byte[] bSalt = new byte[16];
		r.nextBytes(bSalt);
		// Convert to a character array
		salt = new String(bSalt).toCharArray();
		
		// Append the salt to the password
		password.concat(new String(salt));
		
		// Hash the salted password, convert to string, and save
		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(password.getBytes("UTF-8"));
		hash = new BigInteger(1, md.digest()).toString(16);
		
		return true;
	}
	
	// Email prompt
	public static boolean emailPrompt() {

		// Use user's console
		Console console = System.console();
		
		// Construct a pattern object
		Pattern p = Pattern.compile(".");
	
		// variables	
		String e = null;
		boolean validEmail = false;
		
		// Enter a valid Email Address
		do {
			System.out.println("\nPlease enter your valid email address.");
			e = console.readLine("email: ");
			// Valid email address pattern (simple checks for: characters/numbers/period@characters/numbers/period.characters/numbers)
			if (p.matches("[a-zA-Z0-9\\.]+@[a-zA-Z0-9\\.]+\\.[a-zA-Z0-9]+", e)) {
				validEmail = true;
			}
		} while (!validEmail);
		
		email = e;
		return true;
	}
	
	// Name prompt
	public static boolean namePrompt() {
		
		// Use user's console
		Console console = System.console();
		
		// variables
		// Construct a pattern object
		Pattern p = Pattern.compile(".");
		String n = null;
		boolean validName = false;
		
		// Is it a valid name?
		do {
			System.out.println("\nPlease enter your first and last name.");
			n = console.readLine("name: ");
			// Checks that there are two names (may use upper/lower characters and dashes
			if (p.matches("[A-Z][a-zA-Z]*\\ [A-Z][a-zA-Z\\-]*", n)) {
				validName = true;
			}
		} while (!validName);
		name = n;
		return true;
	}
	
	// Address prompt
	public static boolean addressPrompt() {
		
		// Use user's console
		Console console = System.console();
		
		// Variables
		Pattern p = Pattern.compile("[^a-zA-Z0-9\\ \\.\\-]");
		String a = null;
		boolean validAddress = false;
		
		// Valid address?
		do {
			System.out.println("\nPlease enter your address.");
			a = console.readLine("address: ");
			// Checks for valid characters/numbers
			if (!p.matcher(a).find()) {
				validAddress = true;
			}
		} while (!validAddress);
		address = a;
		return true;
	}
	
	// Insert user and congratulate
	public static void register()  throws ClassNotFoundException,SQLException,NoSuchAlgorithmException,UnsupportedEncodingException{
		
		// Were all the functions completed and passed?
		if (usernamePrompt() && passwordPrompt() && saltHash() && emailPrompt() && namePrompt() && addressPrompt()) {
			// Insert user
			insertUser();
			System.out.println("\nThank you for joining!");
		}
	}
}
